package com.srmt.document.feishu.internal.core;

import com.lark.oapi.Client;
import com.srmt.feishu.client.FeishuClient;
import com.lark.oapi.service.docx.v1.model.*;
import com.srmt.document.exception.DocumentOperationException;
import com.srmt.document.exception.DocumentNotFoundException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Block操作上下文
 * 
 * 单次API方法调用期间有效的上下文对象，封装一次性获取的所有Blocks及相关操作。
 * 遵循"一次获取，多次使用"原则，避免重复API调用。
 * 
 * 设计原则：
 * 1. 每个实例对应一次文档操作
 * 2. 构造时获取所有blocks（唯一的API调用）
 * 3. 提供各种基于blocks的本地查询和计算方法
 * 4. 不保留任何跨方法调用的缓存
 * 
 * @author srmt
 * @since 2.0.0
 */
public class BlockContext {
    
    private static final Logger logger = LoggerFactory.getLogger(BlockContext.class);
    
    private final String documentId;
    private final List<Block> blocks;
    private final Map<String, Block> blockIdMap;
    
    /**
     * 创建Block操作上下文
     * 
     * @param client 飞书客户端
     * @param documentId 文档ID
     * @throws DocumentOperationException 如果获取blocks失败
     */
    public BlockContext(FeishuClient client, String documentId) throws DocumentOperationException {
        this.documentId = documentId;

        logger.debug("创建 块Context for document: {}", documentId);
        
        // 获取所有blocks（唯一的API调用）
        this.blocks = fetchAllBlocks(client, documentId);
        
        // 对于电子表格类型的Block，获取并填充维度信息
        enrichSheetDimensions(client, blocks);
        
        // 构建ID映射以提高查询效率
        this.blockIdMap = buildBlockIdMap(blocks);
        
        logger.info("块Context created with {} blocks for document: {}", 
                   blocks.size(), documentId);
    }
    
    /**
     * 获取文档ID
     */
    public String getDocumentId() {
        return documentId;
    }
    
    /**
     * 获取所有blocks
     */
    public List<Block> getBlocks() {
        return Collections.unmodifiableList(blocks);
    }

    /**
     * 通过ID获取Block
     * 
     * @param blockId Block ID
     * @return Block对象，如果不存在返回null
     */
    public Block getBlockById(String blockId) {
        return blockIdMap.get(blockId);
    }
    
    /**
     * 通过锚点文本查找Block
     * 
     * @param anchorText 锚点文本
     * @return 包含锚点文本的第一个Block，如果未找到返回null
     */
    public Block findBlockByAnchor(String anchorText) {
        if (anchorText == null || anchorText.isEmpty()) {
            return null;
        }
        
        for (Block block : blocks) {
            String text = BlockUtils.extractTextFromBlock(block);
            if (text != null && text.contains(anchorText)) {
                logger.debug("在块中找到锚点'{}': {}", anchorText, block.getBlockId());
                return block;
            }
        }
        
        logger.debug("在任何块中都未找到锚点文本'{}'", anchorText);
        return null;
    }
    
    /**
     * 查找锚点文本后的第一个表格Block
     * 
     * @param anchorText 锚点文本，如果为null则查找第一个表格
     * @return 表格Block，如果未找到返回null
     */
    public Block findTableAfterAnchor(String anchorText) {
        boolean foundAnchor = (anchorText == null || anchorText.isEmpty());
        
        for (Block block : blocks) {
            if (!foundAnchor) {
                String text = BlockUtils.extractTextFromBlock(block);
                if (text != null && text.contains(anchorText)) {
                    foundAnchor = true;
                }
            } else {
                if (BlockUtils.isTableBlock(block)) {
                    logger.debug("找到表格块: {}", block.getBlockId());
                    return block;
                }
            }
        }
        
        if (!foundAnchor) {
            logger.debug("未找到锚点文本'{}'", anchorText);
        } else {
            logger.debug("锚点'{}'之后未找到表格", anchorText);
        }
        
        return null;
    }
    
    /**
     * 按类型查找所有Blocks
     * 
     * @param blockType Block类型
     * @return 符合类型的Block列表
     */
    public List<Block> findBlocksByType(Integer blockType) {
        List<Block> result = new ArrayList<>();
        
        for (Block block : blocks) {
            if (block.getBlockType() != null && block.getBlockType().equals(blockType)) {
                result.add(block);
            }
        }
        
        logger.debug("找到{}个类型为{}的块", result.size(), blockType);
        return result;
    }
    
    /**
     * 获取所有表格Blocks
     * 
     * @return 表格Block列表
     */
    public List<Block> getAllTableBlocks() {
        List<Block> tables = new ArrayList<>();
        
        for (Block block : blocks) {
            if (BlockUtils.isTableBlock(block)) {
                tables.add(block);
            }
        }
        
        logger.debug("找到{}个表格块", tables.size());
        return tables;
    }
    
    /**
     * 获取页面根Block
     * 
     * @return 页面Block，通常是第一个Block
     */
    public Block getPageBlock() {
        if (!blocks.isEmpty()) {
            // 通常第一个是Page类型的Block
            Block firstBlock = blocks.get(0);
            if (firstBlock.getBlockType() != null && firstBlock.getBlockType() == 1) {
                return firstBlock;
            }
        }
        
        // 如果第一个不是Page类型，尝试查找
        for (Block block : blocks) {
            if (block.getBlockType() != null && block.getBlockType() == 1) {
                return block;
            }
        }
        
        logger.warn("文档中未找到页面块");
        return null;
    }
    
    /**
     * 查找Block的父Block
     * 
     * @param blockId Block ID
     * @return 父Block，如果未找到返回null
     */
    public Block findParentBlock(String blockId) {
        Block targetBlock = getBlockById(blockId);
        if (targetBlock == null || targetBlock.getParentId() == null) {
            return null;
        }
        
        return getBlockById(targetBlock.getParentId());
    }
    
    /**
     * 查找Block的所有子Block
     * 
     * @param parentBlockId 父Block ID
     * @return 子Block列表
     */
    public List<Block> findChildrenBlocks(String parentBlockId) {
        List<Block> children = new ArrayList<>();
        Block parentBlock = getBlockById(parentBlockId);
        
        if (parentBlock == null || parentBlock.getChildren() == null) {
            return children;
        }
        
        for (String childId : parentBlock.getChildren()) {
            Block childBlock = getBlockById(childId);
            if (childBlock != null) {
                children.add(childBlock);
            }
        }
        
        return children;
    }
    
    /**
     * 搜索包含指定文本的所有Blocks
     * 
     * @param searchText 搜索文本
     * @return 包含搜索文本的Block列表
     */
    public List<Block> searchBlocks(String searchText) {
        List<Block> result = new ArrayList<>();
        
        if (searchText == null || searchText.isEmpty()) {
            return result;
        }
        
        for (Block block : blocks) {
            String text = BlockUtils.extractTextFromBlock(block);
            if (text != null && text.contains(searchText)) {
                result.add(block);
            }
        }
        
        logger.debug("找到{}个包含'{}'的块", result.size(), searchText);
        return result;
    }

    // ========== 表格相关方法 ==========

    /**
     * 获取表格的单元格Block（仅适用于Normal Table）
     *
     * 直接计算单元格在children数组中的位置并返回对应的Block，
     * 避免构建整个cellBlocks矩阵。
     *
     * @param tableBlockId 表格Block ID
     * @param row 行索引（从0开始）
     * @param col 列索引（从0开始）
     * @return 单元格Block，如果不存在返回null
     */
    public Block getTableCellBlock(String tableBlockId, int row, int col) {
        Block tableBlock = getBlockById(tableBlockId);
        if (tableBlock == null) {
            logger.warn("表格块未找到: {}", tableBlockId);
            return null;
        }

        // 只支持Normal Table
        if (tableBlock.getTable() == null) {
            logger.warn("不是普通表格块: {}", tableBlockId);
            return null;
        }

        Table table = tableBlock.getTable();
        if (table.getProperty() == null) {
            logger.warn("表格属性为空: {}", tableBlockId);
            return null;
        }

        int columnCount = table.getProperty().getColumnSize();

        // 计算单元格在children数组中的索引
        int cellIndex = row * columnCount + col;

        String[] children = tableBlock.getChildren();
        if (children == null || cellIndex < 0 || cellIndex >= children.length) {
            logger.warn("单元格索引超出范围: [{}, {}], cellIndex={}, children.length={}",
                       row, col, cellIndex, children != null ? children.length : 0);
            return null;
        }

        return getBlockById(children[cellIndex]);
    }

    /**
     * 获取表格维度信息
     *
     * 支持Normal Table和Sheet两种类型。
     *
     * @param tableBlockId 表格Block ID
     * @return [行数, 列数]数组
     * @throws com.srmt.document.exception.TableException 如果不是表格或维度不可用
     */
    public int[] getTableDimensions(String tableBlockId) {
        Block tableBlock = getBlockById(tableBlockId);
        if (tableBlock == null) {
            throw new IllegalArgumentException("表格块未找到: " + tableBlockId);
        }

        // Normal Table
        if (tableBlock.getTable() != null) {
            Table table = tableBlock.getTable();
            if (table.getProperty() == null) {
                throw new IllegalStateException("表格属性为null: " + tableBlockId);
            }

            int rowCount = table.getProperty().getRowSize();
            int columnCount = table.getProperty().getColumnSize();

            logger.debug("普通表格维度: {}x{}, blockId={}", rowCount, columnCount, tableBlockId);
            return new int[]{rowCount, columnCount};
        }

        // Sheet
        if (tableBlock.getSheet() != null) {
            Sheet sheet = tableBlock.getSheet();

            // 检查维度是否可用（应该已经在构造时enriched）
            if (sheet.getRowSize() == null || sheet.getColumnSize() == null) {
                throw new IllegalStateException(
                    "电子表格维度不可用,令牌: " +
                    (sheet.getToken() != null ? sheet.getToken() : "unknown"));
            }

            int rowCount = sheet.getRowSize();
            int columnCount = sheet.getColumnSize();

            logger.debug("电子表格维度: {}x{}, token={}", rowCount, columnCount, sheet.getToken());
            return new int[]{rowCount, columnCount};
        }

        // Bitable
        if (tableBlock.getBitable() != null) {
            throw new UnsupportedOperationException("多维表格维度暂不支持");
        }

        throw new IllegalArgumentException("不是表格块: " + tableBlockId);
    }

    /**
     * 获取表格合并单元格信息（仅适用于Normal Table）
     *
     * @param tableBlockId 表格Block ID
     * @return 合并信息数组，如果没有合并或不适用返回null
     */
    public TableMergeInfo[] getTableMergeInfo(String tableBlockId) {
        Block tableBlock = getBlockById(tableBlockId);
        if (tableBlock == null) {
            logger.warn("表格块未找到: {}", tableBlockId);
            return null;
        }

        // 只支持Normal Table
        if (tableBlock.getTable() == null) {
            logger.debug("不是普通表格,没有合并信息: {}", tableBlockId);
            return null;
        }

        Table table = tableBlock.getTable();
        if (table.getProperty() == null) {
            return null;
        }

        TableMergeInfo[] mergeInfo = table.getProperty().getMergeInfo();

        if (mergeInfo != null) {
            logger.debug("获取表格合并信息: {} 个单元格合并信息", mergeInfo.length);
        } else {
            logger.debug("表格没有合并单元格");
        }

        return mergeInfo;
    }

    // ========== 私有辅助方法 ==========
    
    /**
     * 获取文档的所有blocks（唯一的API调用）
     */
    private static List<Block> fetchAllBlocks(FeishuClient client, String documentId) 
            throws DocumentOperationException {
        logger.debug("获取文档的所有块: {}", documentId);
        
        try {
            // 使用新的 listAllDocumentBlocks 方法，自动处理分页
            // 该方法已被限流和重试装饰器包装，无需直接访问 getRawClient()
            List<Block> allBlocks = client.docx().listAllDocumentBlocks(documentId);

            logger.info("从文档获取了{}个块", allBlocks.size());
            return allBlocks;
            
        } catch (Exception e) {
            if (e instanceof DocumentNotFoundException) {
                throw (DocumentNotFoundException) e;
            }
            if (e instanceof DocumentOperationException) {
                throw (DocumentOperationException) e;
            }
            throw new DocumentOperationException("获取块失败", e);
        }
    }
    
    /**
     * 构建Block ID映射
     */
    private static Map<String, Block> buildBlockIdMap(List<Block> blocks) {
        Map<String, Block> map = new HashMap<>();
        
        for (Block block : blocks) {
            if (block != null && block.getBlockId() != null) {
                map.put(block.getBlockId(), block);
            }
        }
        
        logger.debug("构建了包含{}个条目的块ID映射", map.size());
        return map;
    }
    
    /**
     * 为电子表格类型的Block获取并填充维度信息
     * 
     * @param client 飞书客户端
     * @param blocks Block列表
     */
    private static void enrichSheetDimensions(FeishuClient client, List<Block> blocks) {
        logger.debug("为块丰富工作表维度信息");
        
        for (int i = 0; i < blocks.size(); i++) {
            Block block = blocks.get(i);
            
            // 检查是否为电子表格类型
            if (block.getSheet() != null && block.getSheet().getToken() != null) {
                String token = block.getSheet().getToken();
                logger.debug("找到工作表块,令牌: {}", token);
                
                try {
                    // 解析token获取spreadsheetToken和sheetId
                    String[] parts = parseSheetToken(token);
                    String spreadsheetToken = parts[0];
                    String sheetId = parts[1];
                    
                    // 如果有sheetId，调用Sheets API获取维度信息
                    if (!sheetId.isEmpty()) {
                        // getSheet现在直接返回Sheet对象
                        com.lark.oapi.service.sheets.v3.model.Sheet sheet =
                            client.sheets().getSheet(spreadsheetToken, sheetId);

                        if (sheet != null && sheet.getGridProperties() != null) {

                            int rows = sheet.getGridProperties().getRowCount();
                            int cols = sheet.getGridProperties().getColumnCount();
                            
                            logger.info("从API获取工作表维度: {}x{},令牌: {}", 
                                       rows, cols, token);
                            
                            // 创建新的Sheet对象，包含维度信息
                            Sheet enrichedSheet = Sheet.newBuilder()
                                    .token(token)
                                    .rowSize(rows)
                                    .columnSize(cols)
                                    .build();
                            
                            // 创建新的Block对象，更新Sheet
                            Block enrichedBlock = Block.newBuilder()
                                    .blockId(block.getBlockId())
                                    .blockType(block.getBlockType())
                                    .parentId(block.getParentId())
                                    .children(block.getChildren())
                                    .sheet(enrichedSheet)
                                    .build();
                            
                            // 替换原Block
                            blocks.set(i, enrichedBlock);
                            logger.debug("在索引{}处丰富了工作表块", i);
                        }
                    } else {
                        logger.debug("没有可用的sheetId,跳过令牌的维度丰富: {}", token);
                    }
                    
                } catch (Exception e) {
                    logger.warn("填充工作表维度信息失败,令牌 {}: {}", 
                               token, e.getMessage());
                    // 继续处理其他blocks，不影响整体流程
                }
            }
        }
        
        logger.debug("电子表格 dimension enrichment completed");
    }
    
    /**
     * 解析Sheet的token，分离spreadsheetToken和sheetId
     * 
     * @param token 完整的token字符串
     * @return [spreadsheetToken, sheetId]数组
     */
    private static String[] parseSheetToken(String token) {
        if (token == null || token.isEmpty()) {
            return new String[]{"", ""};
        }
        
        // 查找最后一个下划线的位置
        int lastUnderscoreIndex = token.lastIndexOf('_');
        
        if (lastUnderscoreIndex == -1) {
            // 没有下划线，整个token就是spreadsheetToken，sheetId为空
            return new String[]{token, ""};
        }
        
        if (lastUnderscoreIndex == 0 || lastUnderscoreIndex == token.length() - 1) {
            // 下划线在开头或结尾，格式可能不正确，但仍尝试处理
            return new String[]{token, ""};
        }
        
        String spreadsheetToken = token.substring(0, lastUnderscoreIndex);
        String sheetId = token.substring(lastUnderscoreIndex + 1);
        
        return new String[]{spreadsheetToken, sheetId};
    }
}